import _ from "lodash";
import { isInitArray, calculateSwitch } from "../../../../tools/index";

export class RenderTools {
  canvas: HTMLCanvasElement | null = null;
  context: CanvasRenderingContext2D | null = null;

  constructor(canvas: HTMLCanvasElement) {
    if (canvas instanceof HTMLCanvasElement) {
      this.canvas = canvas;
      const ctx = canvas.getContext("2d", { willReadFrequently: true });
      this.context = ctx;
    }
  }

  mergeImageData(imageData: any, imageRect: DOMRect) {
    if (this.context && imageData && imageRect instanceof DOMRect) {
      const mergedImageData = this.context.getImageData(
        imageRect.left,
        imageRect.top,
        imageRect.width,
        imageRect.height
      );
      for (let i = 0; i < mergedImageData.data.length; i += 4) {
        if (imageData.data[i + 3] > 0) {
          mergedImageData.data[i] = imageData.data[i]; // R
          mergedImageData.data[i + 1] = imageData.data[i + 1]; // G
          mergedImageData.data[i + 2] = imageData.data[i + 2]; // B
          mergedImageData.data[i + 3] = imageData.data[i + 3];
        }
      }
      this.context.putImageData(mergedImageData, imageRect.left, imageRect.top);
    }
  }

  clear() {
    if (this.canvas instanceof HTMLCanvasElement && this.context) {
      const { width, height } = this.canvas;
      this.context.clearRect(0, 0, width, height);
    }
  }

  size() {
    if (this.canvas instanceof HTMLCanvasElement) {
      return [this.canvas.width, this.canvas.height];
    }
    return [0, 0];
  }

  run(item: any) {
    if (item && typeof item === "object") {
      const params = item["params"]
      switch (item["action"]) {
        case "clear":
          this.clear();
          break;
        case "divier":
          this.divier(params);
          break;
        case "fill":
          this.fill(params);
          break;
        case "path":
          this.path(params);
          break;
        case "fill-rect":
          this.fillRect(params);
          break;
        case "stroke-rect":
          this.strokeRect(params);
          break;
        case "fill-text":
          this.fillText(params);
          break;
        case "draw-grid":
          this.drawGrid(params);
          break;

      }
    }
  }

  divier(params: any) {
    if (params && typeof params === "object" && this.context) {
      const direction = params["direction"];
      const fill = params["fill"];
      const colorOne = fill[0];
      const colorTwo = fill[1];
      const [width, height] = this.size();
      if (direction === "vertical") {
        const left = params["left"];
        const leftValue = calculateSwitch(width, left);
        const heightValue = height;
        this.context.fillStyle = colorOne;
        this.context.fillRect(0, 0, leftValue, heightValue);
        this.context.fillStyle = colorTwo;
        this.context.fillRect(leftValue, 0, width - leftValue, heightValue);
      }
      if (direction === "horizontal") {
        const top = params["top"];
        const topValue = calculateSwitch(height, top);
        const widthValue = width;
        this.context.fillStyle = colorOne;
        this.context.fillRect(0, 0, widthValue, topValue);
        this.context.fillStyle = colorTwo;
        this.context.fillRect(0, topValue, widthValue, height - top);
      }
    }
  }

  fill(params: any) {
    if (params && typeof params === "object" && this.context) {
      const [width, height] = this.size();
      this.context.fillStyle = params["fill"];
      this.context.fillRect(0, 0, width, height);
    }
  }

  path(params: any) {
    if (params && typeof params === "object" && this.context) {
      const paths = params["paths"];
      const strokeStyle = params["strokeStyle"];
      const lineWidth = params["lineWidth"];

      if (isInitArray(paths)) {
        this.context.beginPath();
        if (strokeStyle) {
          this.context.strokeStyle = strokeStyle;
        }
        if (lineWidth) {
          this.context.lineWidth = lineWidth;
        }
        paths.forEach((path: any, index: number) => {
          if (this.context) {
            if (index === 0) {
              this.context.moveTo(path[0], path[1]);
            } else {
              this.context.lineTo(path[0], path[1]);
            }
          }
        });
        this.context.stroke();
      }
    }
  }

  fillRect(params: any) {
    if (params && typeof params === "object" && this.context) {
      this.context.fillStyle = params["fill"];
      const rect = params["rect"];
      if (rect instanceof DOMRect) {
        this.context.fillRect(rect.left, rect.top, rect.width, rect.height);
      } else {
        const [width, height] = this.size();
        this.context.fillRect(0, 0, width, height);
      }
    }
  }

  strokeRect(params: any) {
    if (params && typeof params === "object" && this.context) {
      const strokeStyle = params["strokeStyle"];
      if (strokeStyle) {
        this.context.strokeStyle = strokeStyle;
      }
      const lineWidth = params["lineWidth"] || 1;
      if (lineWidth) {
        this.context.lineWidth = lineWidth;
      }

      const rect = params["rect"];
      if (rect instanceof DOMRect) {
        this.context.strokeRect(rect.left, rect.top, rect.width, rect.height);
      } else {
        const [width, height] = this.size();
        this.context.strokeRect(0, 0, width, height);
      }
    }
  }

  drawGrid(params: any) {
    if (params && typeof params === "object" && this.context) {
      const strokeStyle = params["strokeStyle"];
      if (strokeStyle) {
        this.context.strokeStyle = strokeStyle;
      }
      const lineWidth = params["lineWidth"] || 1;
      if (lineWidth) {
        this.context.lineWidth = lineWidth;
      }
      const size = params["size"];
      if (Array.isArray(size)) {
        const widthSize = size[0]
        const heightSize = size[1]
        const line = lineWidth / 2
        const [width, height] = this.size();
        const gridWidth = (width - lineWidth) / widthSize
        const gridHeight = (height - lineWidth) / heightSize
        this.context.save();
        this.context.beginPath();
        for (let x = 0; x <= width; x += gridWidth) {
          this.context.moveTo(x + line, 0);
          this.context.lineTo(x + line, height);
        }
        for (let y = 0; y <= height; y += gridHeight) {
          this.context.moveTo(0, y + line);
          this.context.lineTo(width, y + line);
        }
        this.context.closePath();
        this.context.stroke();
        this.context.restore();
      }
    }
  }

  fillText(params: any) {
    if (params && typeof params === "object" && this.context) {
      const textValue = params["text"];
      if (textValue) {
        const textAlign = params["textAlign"] || 'center';
        if (textAlign) {
          this.context.textAlign = textAlign;
        }

        const fillStyle = params["fillStyle"];
        if (fillStyle) {
          this.context.fillStyle = fillStyle;
        }

        const textBaseline = params["textBaseline"] || 'middle';
        if (textBaseline) {
          this.context.textBaseline = textBaseline;
        }

        const direction = params["direction"];
        if (direction) {
          this.context.direction = direction;
        }

        let fontSize = params["fontSize"] || 14;
        if (typeof fontSize === "string") {
          const text = fontSize.match(/[0-9]+(?=px)/g)
          fontSize = text ? _.toNumber(text[0]) : undefined;
        }

        const fontFamily = params["fontFamily"] || 'Georgia';

        this.context.font = `${fontSize + 'px'} ${fontFamily}`;

        const rect = params["rect"];
        if (rect instanceof DOMRect) {
          const textLeft = rect.left + rect.width / 2
          const textTop = rect.top + rect.height / 2
          this.context.fillText(textValue, textLeft, textTop, rect.width);
        } else {
          const [width, height] = this.size();
          this.context.fillText(textValue, width / 2, height / 2, width);
        }
      }
    }
  }

  test() {
    if (this.context) {
      this.context.beginPath(); // 开始路径声明

      this.context.moveTo(100, 100); //移动到某一个坐标
      this.context.lineTo(300, 100); // 建立直线
      this.context.closePath(); // 闭合路径

      this.context.fillRect(0, 0, 100, 100); // 绘制一个填充的矩形。
      this.context.rect(50, 50, 10, 10); // 等同于fillRect?

      this.context.strokeRect(0, 0, 100, 100); // 绘制一个矩形的边框。
      this.context.clearRect(0, 0, 100, 100); // 清除指定的矩形区域，然后这块区域会变的完全透明。

      this.context.arc(50, 50, 40, 0, Math.PI / 2, false); // 绘制弧线

      // this.context.quadraticCurveTo(cp1x, cp1y, x, y); //绘制二次贝塞尔曲线（相当于绘制通过3个随机点的曲线，13点为起止点，2点为控制点）
      // this.context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) //绘制三次贝塞尔曲线

      this.context.strokeStyle = "#000"; // 设置路径颜色
      this.context.lineWidth = 20; // 路径粗细

      const lineCaps = ["butt", "round", "square"];
      // this.context.lineCap = lineCaps[0]; // 路径末端形状 方形 圆形 额外方形（超出起止点一部分）

      const lineJoin = ["round", "bevel", "miter"];
      //  this.context.lineJoin = lineJoin[0]; // 线条与线条间接合处的形状 圆形 三角填充 尖角

      this.context.setLineDash([20, 5]); // 虚线 [实线长度, 间隙长度]
      this.context.lineDashOffset = -0; // 虚线偏移量

      this.context.font = "100px sans-serif";
      this.context.textAlign = "start"; //  start, end, left, right or center
      this.context.textBaseline = "alphabetic"; // top, hanging, middle, alphabetic, ideographic, bottom
      this.context.direction = "inherit"; // ltr, rtl, inherit

      this.context.fillText("天若有情", 10, 100); // 填充文字
      this.context.strokeText("天若有情", 10, 200); // 边框文字

      this.context.stroke(); // 绘制操作

      this.context.fillStyle = "#000"; // 设置填充颜色
      this.context.fill(); // 填充路径操作

      this.context.save(); // 保存默认状态
      this.context.restore(); // 加载默认颜色配置

      this.context.translate(100, 100); // 用来移动 canvas 的原点到指定的位置
      this.context.rotate((Math.PI / 180) * 45); // 旋转坐标轴
      this.context.scale(1, 1); // 位图进行缩小或者放大
      this.context.transform(1, 1, 0, 1, 0, 0); // 变形矩阵

      const compositeType = [
        "source-in", //
        "source-out",
        "source-atop",
        "destination-over",
        "destination-in",
        "destination-out",
        "destination-atop",
        "lighter",
        "darken",
        "lighten", // 保证重叠部分最量的像素
        "xor",
        "copy",
      ];
      //  this.context.globalCompositeOperation = compositeType[0]; // 全局合成操作

      this.context.clip(); // 裁剪路径
    }

  }
}
